import { HRDRoles, eGridSideLength, eROW, eCOL, eDIR } from "./GameConfig";
import { HRDLevels } from "./LevelsConfig";
import DataManager from "./DataManager";

const { ccclass, property } = cc._decorator;
/**
 * 坐标索引，均以左上角为锚点
 * &----&----&----&-----
 * | 00 | 01 | 02 | 03 |
 * &----&----&----&-----
 * | 10 | 11 | 12 | 13 |
 * &----&----&----&-----
 * | 20 | 21 | 22 | 23 |
 * &----&----&----&-----
 * | 30 | 31 | 32 | 33 |
 * &----&----&----&-----
 * | 40 | 41 | 42 | 43 |
 * ---------------------
 */
@ccclass
export default class GameScene extends cc.Component {

    @property(cc.Node)
    nodeMoveArea: cc.Node = null;

    @property(cc.Node)
    nodeCong: cc.Node = null;

    @property(cc.Label)
    labLevelName: cc.Label = null;

    @property(cc.Label)
    labSteps: cc.Label = null;

    nodeRoleArr: Array<cc.Node> = [];

    // 左上角开始放置位置
    m_placeStartPos: cc.Vec2 = cc.v2(0, 0);

    placeArr: Array<any> = [];

    m_startPos: cc.Vec2 = null;
    m_endPos: cc.Vec2 = null;

    m_touchNode: cc.Node = null;

    m_steps: number = 0;

    onLoad() {
        this.addTouchEventListener();
        let currentLevel = DataManager.getIns().getCurrentLevel();
        this._initLevel(currentLevel);
    }

    private addTouchEventListener() {
        this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.node.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
        this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchCancel, this);
    }

    private onTouchStart(event) {
        this.m_startPos = event.touch.getLocation();
        // 找到touch的角色
        let worldPos = this.node.convertToWorldSpace(this.m_startPos);
        for (let i = 0; i < this.nodeRoleArr.length; i++) {
            let curNode = this.nodeRoleArr[i];
            if (curNode && curNode.isValid) {
                let nodePos = this.nodeMoveArea.convertToNodeSpaceAR(worldPos);
                let rect = cc.rect(curNode.getPosition().x, curNode.getPosition().y - curNode.getContentSize().height, curNode.getContentSize().width, curNode.getContentSize().height);
                let isInRect = rect.contains(nodePos);
                if (isInRect) {
                    this.m_touchNode = curNode;
                    let heroData = HRDRoles[this.m_touchNode.name];
                    cc.log("m_touchNode id = " + heroData.name);
                    break;
                }
            }
        }
    }

    private onTouchMove(event) {

    }

    private onTouchEnd(event) {
        this.m_endPos = event.touch.getLocation();
        let dis = this.m_startPos.sub(this.m_endPos).mag();

        if (dis >= 30 && this.m_touchNode) {
            cc.log("滑动了");
            this.moveDirection(this.m_startPos, this.m_endPos);
        }
    }

    private onTouchCancel(event) {
        this.m_endPos = event.touch.getLocation();
        let dis = this.m_startPos.sub(this.m_endPos).mag();

        if (dis >= 30 && this.m_touchNode) {
            cc.log("滑动了cancel");
            this.moveDirection(this.m_startPos, this.m_endPos);
        }
    }

    /**
     * 判断滑动方向
     * @param sPos 
     * @param ePos 
     */
    private moveDirection(sPos: cc.Vec2, ePos: cc.Vec2) {
        let deltaX = Math.abs(ePos.x - sPos.x);
        let deltaY = Math.abs(ePos.y - sPos.y);
        if (deltaX >= deltaY) {
            if (ePos.x > sPos.x) {
                cc.log("### right ###");
                this._moveRole(eDIR.RIGHT);
            } else {
                cc.log("### left ###");
                this._moveRole(eDIR.LEFT);
            }
        } else {
            if (ePos.y > sPos.y) {
                cc.log("### up ###");
                this._moveRole(eDIR.UP);
            } else {
                cc.log("### down ###");
                this._moveRole(eDIR.DOWN);
            }
        }
    }

    private _moveRole(dir: number) {
        if (!this.m_touchNode || !this.m_touchNode.isValid) {
            cc.error("[HuaRongDao] _moveRole m_touchNode error.");
            return;
        }
        switch (dir) {
            case eDIR.UP:
                this._moveUp();
                break;
            case eDIR.DOWN:
                this._moveDown();
                break;
            case eDIR.LEFT:
                this._moveLeft();
                break;
            case eDIR.RIGHT:
                this._moveRight();
                break;
        }
    }

    private _moveUp() {
        let roleData = HRDRoles[this.m_touchNode.name];
        let roleRow = Math.floor(roleData.place / 10);
        let roleCol = roleData.place % 10;
        // 检查索引
        let rowAndCol = this._posTranslateIndex(this.m_touchNode);
        let row = rowAndCol.row;
        let col = rowAndCol.col;
        cc.log("[HuaRongDao] _moveUp row = " + row + "  col = " + col);
        // 检查是否可以移动
        let canMoveUp = true;
        if (row - 1 < 0) {
            canMoveUp = false;
        } else {
            for (let i = col; i < col + roleRow; i++) {
                if (this.placeArr[row - 1][i] != -1) {
                    cc.log("不能移动");
                    canMoveUp = false;
                    break;
                }
            }
        }
        if (canMoveUp) {
            // 移动
            let tarPos = cc.v2(this.m_touchNode.getPosition().x, this.m_touchNode.getPosition().y + eGridSideLength);
            this.m_touchNode.runAction(cc.sequence(cc.moveTo(0.1, tarPos), cc.callFunc(() => {
                this._checkVictory();
            })));
            // 数组数据更新
            for (let i = col; i < col + roleRow; i++) {
                this.placeArr[row - 1][i] = 1;
                this.placeArr[row + roleCol - 1][i] = -1;
            }
            this.labSteps.string = String(++this.m_steps);
            this._printDataArr();
        }
    }

    private _moveDown() {
        let roleData = HRDRoles[this.m_touchNode.name];
        let roleRow = Math.floor(roleData.place / 10);
        let roleCol = roleData.place % 10;
        // 检查索引
        let rowAndCol = this._posTranslateIndex(this.m_touchNode);
        let row = rowAndCol.row;
        let col = rowAndCol.col;
        cc.log("[HuaRongDao] _moveDown row = " + row + "  col = " + col);
        // 检查是否可以移动
        let canMoveDown = true;
        if (row + 1 >= eROW) {
            canMoveDown = false;
        } else {
            for (let i = col; i < col + roleRow; i++) {
                if (this.placeArr[row + roleCol][i] != -1) {
                    cc.log("不能移动");
                    canMoveDown = false;
                    break;
                }
            }
        }
        if (canMoveDown) {
            // 移动
            let tarPos = cc.v2(this.m_touchNode.getPosition().x, this.m_touchNode.getPosition().y - eGridSideLength);
            this.m_touchNode.runAction(cc.sequence(cc.moveTo(0.1, tarPos), cc.callFunc(() => {
                this._checkVictory();
            })));
            // 数组数据更新
            for (let i = col; i < col + roleRow; i++) {
                this.placeArr[row + roleCol][i] = 1;
                this.placeArr[row][i] = -1;
            }
            this.labSteps.string = String(++this.m_steps);
            this._printDataArr();
        }
    }

    private _moveLeft() {
        let roleData = HRDRoles[this.m_touchNode.name];
        let roleRow = Math.floor(roleData.place / 10);
        let roleCol = roleData.place % 10;
        // 检查索引
        let rowAndCol = this._posTranslateIndex(this.m_touchNode);
        let row = rowAndCol.row;
        let col = rowAndCol.col;
        cc.log("[HuaRongDao] _moveLeft row = " + row + "  col = " + col);
        // 检查是否可以移动
        let canMoveLeft = true;
        if (col - 1 < 0) {
            canMoveLeft = false;
        } else {
            for (let i = row; i < row + roleCol; i++) {
                if (this.placeArr[row + roleRow - 1][col - 1] != -1) {
                    cc.log("不能移动");
                    canMoveLeft = false;
                    break;
                }
            }
        }
        if (canMoveLeft) {
            // 移动
            let tarPos = cc.v2(this.m_touchNode.getPosition().x - eGridSideLength, this.m_touchNode.getPosition().y);
            this.m_touchNode.runAction(cc.sequence(cc.moveTo(0.1, tarPos), cc.callFunc(() => {
                this._checkVictory();
            })));
            // 数组数据更新
            for (let i = row; i < row + roleCol; i++) {
                this.placeArr[i][col - 1] = 1;
                this.placeArr[i][col + roleRow - 1] = -1;
            }
            this.labSteps.string = String(++this.m_steps);
            this._printDataArr();
        }
    }

    private _moveRight() {
        let roleData = HRDRoles[this.m_touchNode.name];
        let roleRow = Math.floor(roleData.place / 10);
        let roleCol = roleData.place % 10;
        // 检查索引
        let rowAndCol = this._posTranslateIndex(this.m_touchNode);
        let row = rowAndCol.row;
        let col = rowAndCol.col;
        cc.log("[HuaRongDao] _moveRight row = " + row + "  col = " + col);
        // 检查是否可以移动
        let canMoveRight = true;
        if (col + 1 >= eCOL) {
            canMoveRight = false;
        } else {
            for (let i = row; i < row + roleRow; i++) {
                if (this.placeArr[i][col + 1] != -1) {
                    cc.log("不能移动");
                    canMoveRight = false;
                    break;
                }
            }
        }
        if (canMoveRight) {
            // 移动
            let tarPos = cc.v2(this.m_touchNode.getPosition().x + eGridSideLength, this.m_touchNode.getPosition().y);
            this.m_touchNode.runAction(cc.sequence(cc.moveTo(0.1, tarPos), cc.callFunc(() => {
                this._checkVictory();
            })));
            // 数组数据更新
            for (let i = row; i < row + roleCol; i++) {
                this.placeArr[i][col + 1] = 1;
                this.placeArr[i][col - roleRow + 1] = -1;
            }
            this.labSteps.string = String(++this.m_steps);
            this._printDataArr();
        }
    }

    /**
     * 判断游戏是否过关
     */
    private _checkVictory(): boolean {
        let pass = false;
        // let roleNode = this.nodeMoveArea.getChildByName("1");

        let roleNode = null;
        for (let i = 0; i < this.nodeRoleArr.length; i++) {
            let node = this.nodeRoleArr[i];
            if (node.name == "1") {
                roleNode = node;
            }
        }

        if (roleNode && roleNode.isValid) {
            let rowAndCol = this._posTranslateIndex(roleNode);
            if (rowAndCol.row === 3 && rowAndCol.col === 1) {
                pass = true;
            }
        }
        if (pass) {
            cc.log("恭喜过关");
            this.nodeCong.active = true;
            // 过关逻辑
        }
        return pass;
    }

    /**
     * 辅助打印数组信息
     */
    private _printDataArr() {
        for (let i = 0; i < this.placeArr.length; i++) {
            cc.log("[" + [this.placeArr[i][0]] + ", " + [this.placeArr[i][1]] + ", " + [this.placeArr[i][2]] + ", " + [this.placeArr[i][3]] + "]");
        }
    }

    /**
     * 通过position获取节点占用位置的索引
     * 注意：这里的位置有可能是带很多小数点的浮点数，所以使用Math.round
     * @param node 
     */
    private _posTranslateIndex(node: cc.Node) {
        let rowAndCol: any = {};
        for (let i = 0; i < eCOL; i++) {
            for (let j = 0; j < eROW; j++) {
                let xEquel = this.m_placeStartPos.x + i * eGridSideLength === Math.round(node.getPosition().x);
                let yEquel = this.m_placeStartPos.y - j * eGridSideLength === Math.round(node.getPosition().y);
                if (xEquel && yEquel) {
                    rowAndCol.row = j;
                    rowAndCol.col = i;
                    return rowAndCol;
                }
            }
        }
        cc.error("[HuaRongDao] _posTranslateIndex get wrong!!!");
        return null;
    }

    /**
     * 重置游戏数据
     */
    private _resetData() {
        this.m_placeStartPos = cc.v2(-this.nodeMoveArea.getContentSize().width / 2, this.nodeMoveArea.getContentSize().height / 2);
        this.nodeRoleArr = [];
        this.nodeMoveArea.removeAllChildren(true);

        this.placeArr = [];
        for (let i = 0; i < eROW; i++) {
            let arr: Array<number> = [];
            for (let j = 0; j < eCOL; j++) {
                arr.push(-1);
            }
            this.placeArr.push(arr);
        }

        this.m_steps = 0;
    }

    /**
     * 初始化关卡信息
     * @param lv 关卡等级
     */
    private _initLevel(lv: string) {
        DataManager.getIns().setCurrentLevel(lv);
        this._resetData();
        this.labLevelName.string = HRDLevels[lv].name;
        let leveInfo = HRDLevels[lv].level;
        let index = 0;
        let roleConfig = null;
        for (let i = 0; i < eROW; i++) {
            for (let j = 0; j < eCOL; j++) {
                index = i * eCOL + j;
                let heroID = leveInfo[index];
                if (heroID === 0 || this.placeArr[i][j] === 1) {
                    continue;
                }

                roleConfig = HRDRoles[heroID];
                if (roleConfig) {
                    this._createSprite(heroID, cc.v2(this.m_placeStartPos.x + j * eGridSideLength, this.m_placeStartPos.y - i * eGridSideLength));
                    let place = roleConfig.place;
                    let front = Math.floor(place / 10);
                    let rear = place % 10;
                    for (let k = i; k < i + rear; k++) {
                        for (let m = j; m < j + front; m++) {
                            if (this.placeArr[k][m]) {
                                this.placeArr[k][m] = 1;
                            }
                        }
                    }
                }
            }
        }
    }

    private _createSprite(id: string, pos: cc.Vec2) {
        let roleData = HRDRoles[id];
        if (roleData) {
            let url = "images/" + roleData.spriteFrame;
            cc.loader.loadRes(url, cc.SpriteFrame, (err, spriteFrame) => {
                if (err) {
                    cc.error("[CCUtils] createSprite err = " + err);
                    return;
                } else {
                    let node = new cc.Node(id);
                    node.setAnchorPoint(cc.v2(0, 1));
                    let sprite = node.addComponent(cc.Sprite);
                    sprite.spriteFrame = spriteFrame;
                    node.setPosition(pos);

                    this.nodeMoveArea.addChild(node);
                    this.nodeRoleArr.push(node);
                }
            });
        }
    }

    public onBtnFrontLevel(event: cc.Event, data: string) {
        if (event.type === cc.Node.EventType.TOUCH_END) {
            let frontLevel = DataManager.getIns().getFrontLevel();
            if (frontLevel) {
                this._initLevel(frontLevel);
            } else {
                cc.log('这是第一关！');
            }
        }
    }

    public onBtnReset(event: cc.Event, data: string) {
        if (event.type === cc.Node.EventType.TOUCH_END) {
            let frontLevel = DataManager.getIns().getCurrentLevel();
            this._initLevel(frontLevel);
        }
    }

    public onBtnNextLevel(event: cc.Event, data: string) {
        if (event.type === cc.Node.EventType.TOUCH_END) {
            let nextLevel = DataManager.getIns().getNextLevel();
            if (nextLevel) {
                this._initLevel(nextLevel);
                this.nodeCong.active = false;
            } else {
                cc.log('这是最后一关了！');
            }
        }
    }

    public onBtnMainMenu(event: cc.Event, data: string) {
        if (event.type === cc.Node.EventType.TOUCH_END) {
            cc.director.loadScene('MainScene');
        }
    }

}
